import * as Cesium from '@cesiumjs';
import {
  g3x_defineClassProperties,
} from "@g3x/utils";
import {
  WaterType,
} from "@g3v/Materials";

export default function(Ctor) {
  g3x_defineClassProperties(Ctor, [{
    'key': "_createDebugView",
    'value': function _createDebugView() {
      var material = Cesium.Material.fromType("Image");
      var quad = new Cesium.ViewportQuad(new Cesium.BoundingRectangle(0x0, 0x64, 0x12c, 0x12c));
      quad.material = material;
      this._debugViewportQuad = this._scene.primitives.add(quad);
      if (this._getWaterReflectTexture()) {
        material.uniforms.image = that._getWaterReflectTexture();
      }
    }
  }, {
    'key': "debugShow",
    'value': function debugShow(show) {
      this._debugViewportQuad.show = show;
    }
  }, {
    'key': 'isDebugShow',
    'value': function isDebugShow() {
      return this._debugViewportQuad.show;
    }
  }, {
    'key': "_getWaterReflectTexture",
    'value': function _getWaterReflectTexture() {
      return this._wrfbo._colorTexture;
    }
  }, {
    'key': "_getWaterReflectTextureChangedEvent",
    'value': function _getWaterReflectTextureChangedEvent() {
      return this._wrfbo._textureChangedEvent;
    }
  }, {
    'key': "_createWaterMaterial",
    'value': function _createWaterMaterial() {
      WaterType.init();
      const specularMap = Cesium.buildModuleUrl("Assets/Textures/waterNormals.jpg");
      const normalMap = Cesium.buildModuleUrl("Assets/Textures/waterNormals.jpg");
      var material = new Cesium.Material({
        fabric: {
          type: WaterType.type,
          'uniforms': {
            specularMap,
            normalMap,
            'frequency': 0x1388,
            'animationSpeed': 0.05,
            'amplitude': 0x2,
            'width': 0x64,
            'height': 0x64
          }
        }
      });
      var _this = this;
      material._uniforms.specularMap_0 = function() {
        return _this._wrfbo._colorTexture || _this._scene.context.defaultTexture;
      };
      return material;
    }
  }, {
    'key': "createWaterPolygonPrimitive",
    'value': function createWaterPolygonPrimitive(positions, ground) {
      var _this = this;
      var _scene = this._scene;
      var primitive = void 0x0;
      var geometry = void 0x0;
      if (ground) {
        geometry = Cesium.PolygonGeometry.fromPositions({
          'vertexFormat': Cesium.MaterialAppearance.MaterialSupport.ALL.vertexFormat,
          'positions': positions
        });
        primitive = _scene.groundPrimitives.add(new Cesium.GroundPrimitive({
          'geometryInstances': new Cesium.GeometryInstance({
            'geometry': geometry
          }),
          'appearance': new Cesium.MaterialAppearance({
            'materialSupport': Cesium.MaterialAppearance.MaterialSupport.ALL
          }),
          'classificationType': Cesium.ClassificationType.BOTH
        }));
      } else {
        geometry = Cesium.CoplanarPolygonGeometry.fromPositions({
          'positions': positions,
          'vertexFormat': Cesium.MaterialAppearance.MaterialSupport.ALL.vertexFormat,
        });
        primitive = _scene.primitives.add(new Cesium.Primitive({
          'geometryInstances': new Cesium.GeometryInstance({
            geometry
          }),
          'appearance': new Cesium.MaterialAppearance({
            'materialSupport': Cesium.MaterialAppearance.MaterialSupport.ALL
          })
        }));
      }
      primitive.appearance.material = this._createWaterMaterial();
      this._scratchCarto = new Cesium.Cartographic();
      const coord3s = positions.map(function(e) {
        const {
          longitude,
          latitude,
          height
        } = Cesium.Cartographic.fromCartesian(e, undefined, _this._scratchCarto);
        return [longitude, latitude, height];
      });
      const NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY;
      const initialMax = [NEGATIVE_INFINITY, NEGATIVE_INFINITY, NEGATIVE_INFINITY];
      const maxCoords = coord3s.reduce(function(total, currentValue) {
        total.forEach(function(e, i) {
          return total[i] = currentValue[i] > e ? currentValue[i] : e;
        });
        return total;
      }, initialMax);
      const POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
      const initialMin = [POSITIVE_INFINITY, POSITIVE_INFINITY, POSITIVE_INFINITY];
      const minCoords = coord3s.reduce(function(total, currentValue) {
        total.forEach(function(e, i) {
          return total[i] = currentValue[i] < e ? currentValue[i] : e;
        });
        return total;
      }, initialMin);

      const coords2 = minCoords.map(function(e, index) {
        return (e + maxCoords[index]) / 2;
      });
      const Cartesian3 = Cesium.Cartesian3;
      const centerPos = Cartesian3.fromRadians.apply(Cartesian3, [...coords2]);
      const vx = (maxCoords[0] - minCoords[0]) * 0x615299;
      const vy = (maxCoords[1] - minCoords[1]) * (0x615299 * Math.cos(coords2[1]));
      primitive.appearance.material.uniforms.sizeAndVelocity.x = vx;
      primitive.appearance.material.uniforms.sizeAndVelocity.y = vy;
      primitive.centerPos = centerPos;
      primitive.radius = Math.max(vx, vy) * 0.5;
      const {height} = Cesium.Cartographic.fromCartesian(centerPos);
      primitive.waterHeight = height;
      this._trackPrimitive(primitive);
      return primitive;
    }
  }, {
    'key': "destroyWaterPolygonPrimitive",
    'value': function destroyWaterPolygonPrimitive(primitive) {
      if (~this._trackedPrimitives.indexOf(primitive)) {
        this._untrackPrimitive(primitive);
        if (this._scene.primitives.contains(primitive)) {
          this._scene.primitives.remove(primitive);
        }
        if (this._scene.groundPrimitives.contains(primitive)) {
          this._scene.groundPrimitives.remove(primitive);
        }
      } else {
        console.error("The polygon may not water!");
      }
    }
  }, {
    'key': '_trackPrimitive',
    'value': function _trackPrimitive(primitive) {
      if (!~this._trackedPrimitives.indexOf(primitive)) {
        this._trackedPrimitives.push(primitive);
      }
    }
  }, {
    'key': "_untrackPrimitive",
    'value': function _untrackPrimitive(primitive) {
      var index = this._trackedPrimitives.indexOf(primitive);
      if (index >= -1) {
        this._trackedPrimitives.splice(index, 1);
      }
    }
  }, {
    'key': "isDestroyed",
    'value': function isDestroyed() {
      return false;
    }
  }, {
    'key': "destroy",
    'value': function destroy() {
      this._disposeListener = this._disposeListener && this._disposeListener();
      this._wrfbo = this._wrfbo && this._wrfbo.destroy();
      this._trackedPrimitives.length = []; // ???
      return Cesium.destroyObject(this);
    }
  }]);
}
